using System;
using System.Collections.Generic;
using System.Data;
using System.Data.Common;
using System.Linq;
using System.Linq.Expressions;
using System.Reflection;
using System.Text;
using System.Threading;
using FastReflectionLib;
using Microsoft.Practices.EnterpriseLibrary.Caching;
using Microsoft.Practices.EnterpriseLibrary.Data;
using Microsoft.Practices.EnterpriseLibrary.Data.Sql;

namespace HF.Repository.MSSql
{
    public static class SqlRepositoryHelper
    {
        private static SqlDatabase _sqlDatabase;
        private static readonly ReaderWriterLockSlim sqlDatabaseLock;

        static SqlRepositoryHelper()
        {
            sqlDatabaseLock = new ReaderWriterLockSlim();
        }

        //internal static string ConnString
        //{
        //    get { return ConfigurationManager.ConnectionStrings["MySqlConnection"].ConnectionString; }
        //}

        public static IDbTransaction BeginTransaction()
        {
            DbConnection con = CreateDatabase().CreateConnection();
            con.Open();
            DbTransaction transaction = con.BeginTransaction();
            return transaction;
        }

        public static void EndTransaction(IDbTransaction transaction)
        {
            //   transaction.Connection.Close();
            //  transaction.Connection.Dispose();
        }


        internal static SqlDatabase CreateDatabase()
        {
            return DatabaseFactory.CreateDatabase() as SqlDatabase;
        }

        internal static SqlDatabase CreateDatabase(string conn)
        {
            CacheGetter<SqlDatabase> getter = (out SqlDatabase p) =>
                                                  {
                                                      p = _sqlDatabase;
                                                      return p != null;
                                                  };

            return CacheHelper.Get(getter,
                                   () => new SqlDatabase(conn),
                                   p => _sqlDatabase = p,
                                   sqlDatabaseLock);
        }

        public static string ToSqlValue(this object str)
        {
            return GetSqlValueString(str);
        }

        internal static string GetSqlValueString(object obj)
        {
            if (obj == null)
            {
                return "null";
            }

            if (obj is int || obj is double || obj is decimal)
            {
                return obj.ToString();
            }
            if (obj is bool)
            {
                return bool.Parse(obj.ToString()) ? "1" : "0";
            }

            if (obj is string)
            {
                var str = obj as string;
                int idx = 0;
                while (idx < str.Length)
                {
                    if (str[idx++] > 0x7f)
                    {
                        return string.Format(" N'{0}' ", str.Replace("\'", "\'\'"));
                    }
                }
            }
            else if (obj is DateTime)
            {
                var mindt = (DateTime)System.Data.SqlTypes.SqlDateTime.MinValue; //DateTime.Parse("1900-1-1");
                if ((DateTime)obj < mindt)
                    obj = mindt;
                return string.Format(" '{0}' ", ((DateTime) obj));
            }

            return string.Format(" '{0}' ", obj.ToString().Replace("\'", "\'\'"));
        }


        ///// <summary>
        ///// 
        ///// </summary>
        ///// <returns>(col1,xol2)</returns>
        // static string GetInsertString(Type type)
        //{
        //    string[] props =
        //        RepositoryReflectionCache.GetPropertyInfos(type).Select(p => string.Format("[{0}]", p.Name)).ToArray();

        //    return string.Format("( {0} )", string.Join(",", props));
        //}

        internal static string GetInsertString(RepositoryModel model)
        {
            var sb = new StringBuilder();

            var ps = RepositoryReflectionCache.GetPropertyInfos(model.GetType());
            var list = new List<string>(ps.Length);
            sb.Append("() values (");
            foreach (var info in ps)
            {
                var value = info.FastGetValue(model);
                if (value == null) continue;
                list.Add(string.Format("[{0}]", info.Name));
                sb.AppendFormat("{0},", value.ToSqlValue());
            }

            if (sb.Length > 1)
            {
                --sb.Length;
            }
            sb.Append(")");

            var str = string.Join(",", list.ToArray());
            sb.Insert(1, str);
            list.Clear();
            list = null;
            str = sb.ToString();
            sb.Length = 0;
            sb = null;
            return str;
        }


        internal static string GetUpdateString(RepositoryModel model, RepositoryModel old)
        {

            var sb = new StringBuilder();
            var ps = RepositoryReflectionCache.GetPropertyInfos(model.GetType());
            foreach (var info in ps)
            {
                var value = info.FastGetValue(model);
                var oldvalue = info.FastGetValue(old);

                if (!value.TruelyEquals(oldvalue))
                {
                    sb.AppendFormat(" {0} = {1},", info.Name, value.ToSqlValue());
                }

            }
            if (sb.Length > 1)
            {
                --sb.Length;
            }

            return sb.ToString();
        }

        public static ICacheManager GetCacheManager()
        {
            return CacheFactory.GetCacheManager();
        }
    }
}